package org.dreamwork.jasmine2.engine;

import org.dreamwork.jasmine2.javac.JasmineFileInfo;
import org.dreamwork.jasmine2.javac.JasmineClassLoader;
import org.dreamwork.jasmine2.javac.JasmineCreator2;
import org.dreamwork.jasmine2.web.controls.Page;
import org.dreamwork.jasmine2.parser.TaglibDirective;
import org.dreamwork.jasmine2.parser.ParseException;
import org.dreamwork.jasmine2.parser.CharsetDetector;
import org.apache.log4j.Logger;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
import java.net.URL;
import java.net.URLConnection;

/**
 * Created by IntelliJ IDEA.
 * User: seth
 * Date: 2009-10-19
 * Time: 11:13:19
 */
public class PagePreparer {
    private File srcdir, outdir;
    private String pageFileName;

    private static final Logger logger = Logger.getLogger (PagePreparer.class);

    public PagePreparer (String pageFileName, File srcdir, File outdir) {
        this.pageFileName = pageFileName;
        this.srcdir = srcdir;
        this.outdir = outdir;
    }

    public Page loadPage () throws FileNotFoundException, Exception {
        JasmineFileInfo info = new JasmineFileInfo (pageFileName, srcdir, outdir);
        if (logger.isDebugEnabled ()) {
            logger.debug ("info.getClassName () = " + info.getClassName ());
            logger.debug ("info.getFileName () = " + info.getFileName ());
            logger.debug ("info.getOrignalPath () = " + info.getOrignalPath ());
            logger.debug ("info.getPackageName () = " + info.getPackageName ());
            logger.debug ("info.getPackagePath () = " + info.getPackagePath ());
            logger.debug ("info.getSrcFile () = " + info.getSrcFile ());
            logger.debug ("info.getClassFile () = " + info.getClassFile ());
        }

        HttpContext context = HttpContext.current ();
        HttpServletRequest request = context.getRequest ();

        PageScaner scaner = new PageScaner (request.getServletPath ());
        List<TaglibDirective> list;

        Page page = null;
        try {
            list = scaner.scan ();
        } catch (FileNotFoundException ex) {
//            response.sendError (HttpServletResponse.SC_NOT_FOUND);
            return null;
        }

        String currentPath = request.getServletPath ();
        int pos = currentPath.lastIndexOf ("/");
        if (pos != -1) currentPath = currentPath.substring (0, pos);

        Map<String, String> map = new HashMap<String, String> ();
        if (list != null) for (TaglibDirective taglib : list) {
            String userControlFile = currentPath + '/' + taglib.getURI ();
            logger.debug ("find user control: " + userControlFile);
            JasmineFileInfo fileInfo = new JasmineFileInfo (userControlFile, srcdir, outdir);
            if (needCreatePage (fileInfo)) {
                logger.debug ("preparing to create user control " + userControlFile);
                createPage (/*request, */fileInfo, null);
                logger.debug (userControlFile + " created as " + fileInfo.getClassFile ());
            }
            map.put (taglib.getName (), fileInfo.getClassName ());
        }

        if (needCreatePage (info)) createPage (/*request, */info, map.size () == 0 ? null : map);
        JasmineClassLoader loader = new JasmineClassLoader (info.getClassDir ());
        page = loader.load (info.getClassName ());

        return page;
    }

    private boolean needCreatePage (JasmineFileInfo info) {
        ServletContext context = HttpContext.current ().getApplication ();
        String root = context.getRealPath ("/");
        if (!info.getClassFile ().exists ()) return true;
        else if (root != null) {
            File jsp = new File (context.getRealPath (info.getOrignalPath ()));
            if (jsp.lastModified () > info.getClassFile ().lastModified ())
                return true;
        }
        return false;
    }

    private void createPage (JasmineFileInfo info, Map<String, String> userControls) throws IOException, ParseException {
        String charset;
        Reader in;
        ServletContext context = HttpContext.current ().getApplication ();

        String root = context.getRealPath ("/");
        if (root == null) { // war
            URL url = getClass ().getResource (info.getOrignalPath ());
            URLConnection conn = url.openConnection ();
            charset = new CharsetDetector (url).getCharset ();
            in = new InputStreamReader (conn.getInputStream (), charset);
        } else {
            File jsp = new File (context.getRealPath (info.getOrignalPath ()));
            charset = new CharsetDetector (jsp.toURL ()).getCharset ();
            in = new InputStreamReader (new FileInputStream (jsp), charset);
        }

        JasmineCreator2 creator = new JasmineCreator2 ();
        creator.setCompileClassPath (getClassPath ());
        if (userControls != null) {
            creator.setUserControl (userControls);
            creator.setUserControlClassPath (info.getClassDir ());
        }
        creator.setReader (in);
        creator.create (info);
    }

    private String getClassPath () {
        ServletContext context = HttpContext.current ().getApplication ();
        String tomcat_cp = (String) context.getAttribute (TOMCAT_CONTEXT_CLASSPATH);
        String webshere_cp = (String) context.getAttribute (WEBSPHERE_CONTEXT_CLASSPATH);
        String separtator = File.pathSeparator;
        StringBuffer classPath = new StringBuffer ()
                .append (tomcat_cp == null ? "" : tomcat_cp).append (separtator)
                .append (webshere_cp == null ? "" : webshere_cp).append (separtator)
                .append (System.getProperty (SYSTEM_CLASSPATH));

        return classPath.toString ();
    }

    public static final String TOMCAT_CONTEXT_CLASSPATH = "org.apache.catalina.jsp_classpath";
    public static final String SYSTEM_CLASSPATH = "java.class.path";
    public static final String WEBSPHERE_CONTEXT_CLASSPATH = "com.ibm.websphere.servlet.application.classpath";
    public static final String J2EE_TEMP_DIR = "javax.servlet.context.tempdir";
}
